import hashlib
import os
import uuid
import json

from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from studentweb.models import Faculty,Major,Student,StudentI
from studentweb.serializer import FacultySerialzer,MajorSerialzer,StudentSerialzer
from django_filters.rest_framework import DjangoFilterBackend  # 实现筛选的后台模块
from django_filters import FilterSet, filters
from studentweb.filter import FacultyFilter,MajorFilter,StudentFilter
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.filters import SearchFilter # 搜索
from studentweb.paginations import MyPageNumberPagination  # 分页
# 引入JsonResponse模块
# 引入处理Excel模块
from django.http import JsonResponse
import openpyxl
from utils import myupload
# from 导入setting
from django.conf import settings
from django.views.decorators.csrf import csrf_protect

# Create your views here.


# Faculty视图
class FacultyViewSet(ModelViewSet):
    """
           create:
           创建院系信息
           retrieve:
           获取院系信息详情数据
           update:
           完整更新院系信息
           partial_update:
           部分更新院系信息
           destroy:
           删除院系信息
           list:
           获取所有院系信息

           """
    queryset = Faculty.objects.all()
    serializer_class = FacultySerialzer
    filterset_fields = ('name',)



# --- Major视图---
class MajorViewSet(ModelViewSet):
    """
    create:
    创建专业信息
    retrieve:
    获取专业信息详情数据
    update:
    完整更新专业信息
    partial_update:
    部分更新专业信息
    destroy:
    删除专业信息
    list:
    获取所有专业信息

    """
    queryset = Major.objects.all()
    serializer_class = MajorSerialzer
    filterset_fields = ('name', 'faculty')
    #filter_class = MajorFilter


# --- Student视图---
class StudentViewSet(ModelViewSet):
    """
    create:
    创建学生信息
    retrieve:
    获取学生信息详情数据
    update:
    完整更新学生信息
    partial_update:
    部分更新学生信息
    destroy:
    删除学生信息
    list:
    获取所有学生信息

    """

    queryset = Student.objects.all()
    serializer_class = StudentSerialzer
    pagination_class = MyPageNumberPagination

    #filterset_fields = ('sno', 'name', 'mobile', 'email', 'major')
    # 自定义模糊搜索
    # http://127.0.0.1:8000/api/v1/students/?name=王
    # http://127.0.0.1:8000/api/v1/students/?name=&son=&mobile=18900998909
    filterset_class = StudentFilter
    # # 设置筛选后台

    # # 指定筛选的类
    # # 指定查找匹配的字段 --- 学号、姓名、电话、邮箱、地址
    search_fields = ('sno', 'name', 'mobile', 'email', 'address')
    # 新增
    def create(self,request,*args,**kwargs):
        # 接收传递的值
        rec = request.data
        # 添加
        try:
            Student.objects.create(sno=rec.get('sno'), name=rec.get('name'), gender=rec.get('gender'),
                                   birthday=rec.get('birthday'), major_id=rec.get('major'),
                                   mobile=rec.get('mobile'), email=rec.get('email'), address=rec.get('address'),
                                   image=rec.get('image'))
            return Response({'msg':'添加成功'},status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response({"error":'添加学生失败'},status=status.HTTP_400_BAD_REQUEST)

    def update(self, request, *args, **kwargs):
        # 接收传递的值
        rec = request.data
        # 添加
        try:
            Student.objects.filter(pk=kwargs.get('pk')).update(name=rec.get('name'), gender=rec.get('gender'),
                                                               birthday=rec.get('birthday'), major_id=rec.get('major'),
                                                               mobile=rec.get('mobile'), email=rec.get('email'),
                                                               address=rec.get('address'), image=rec.get('image'))
            return Response({'msg': '修改成功！'}, status=status.HTTP_201_CREATED)
        except Exception as e:
            return Response({'error': '修改学生失败'}, status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['post'],detail=False)
    def upload(self,request,*args,**kwargs):
        # 接受前端传递文件
        rev_file = request.FILES.get('file')
        # 判断是否
        if not rev_file:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        # 调用
        res = myupload.update_file(rev_file,'images',2)
        #返回
        return Response(res)


# 报403
@csrf_protect
def upload(request):
    # 接收上传的文件
    rev_file = request.FILES.get('avatar')
    # 判断 是否有文件
    if not rev_file:
        return JsonResponse({"code":0,'msg':"图片不存在"})
    # 获取一个唯一的名字 uuid+has
    new_name = get_random_str()
    # 准备写入的url
    file_path = os.path.join(settings.MEDIA_ROOT,new_name + os.path.splitext(rev_file.name)[1])
    # 开始写入到本次磁盘
    try:
        f = open(file_path,'wb')
        # 多次写入
        for i in rev_file.chunks():
            f.write(i)
        # 关闭
        f.close()
        return JsonResponse({'code':1,'name':new_name + os.path.splitext(rev_file.name)[1]})

    except Exception as e:
        return JsonResponse({"code":0,'msg':str(e)})


def get_random_str():
    # 获取uuid的随机数
    uuid_val = uuid.uuid4()
    # 获取uuid的随机数字符串
    uuid_str = str(uuid_val).encode('utf-8')
    # 获取md5
    md5 = hashlib.md5()
    # 拿到uuid
    md5.update(uuid_str)
    return md5.hexdigest()


def export_student_excel(request):
    # 获取数据到excel
    # 获取所有学生的信息
    obj_students = Student.objects.all().values()
    # 转为list
    students = list(obj_students)
    # 准备名称
    excel_name = get_random_str() + ".xlsx"
    # 准备写入的路径
    path = os.path.join(settings.MEDIA_ROOT,excel_name)
    # 写入excel
    write_to_excel(students,path)
    return JsonResponse({"code":1,'name':excel_name})


def read_excel_dict(path:str):
    # 读取excel数据，存储为字典
    # 实例化一个sheet
    workbook = openpyxl.load_workbook(path)
    sheet = workbook['student']
    # 定义一个变量存储最终的数据
    students = []
    # 准备key
    keys = ['sno','name','gender','birthday','mobile','email','address']
    #遍历
    for row in sheet.rows:
        # 定义一个临时字典
        temp_dict = {}
        # 组合值和key
        for index,cell in enumerate(row):
            # 组合
            temp_dict[keys[index]] = cell.value
        # 附加到list中
        students.append(temp_dict)
    return students


def write_to_excel(data:list,path:str):
    # 把数据库写入到excel
    # 实例化一个workbook
    workbook = openpyxl.Workbook()
    # 激活一个sheet
    sheet = workbook.active
    # 为sheet命名
    sheet.title = 'student'
    # 准备keys
    keys = data[0].keys()
    # 准备写入数据
    for index,item in enumerate(data):
        # 遍历每一个元素
        for k,v in enumerate(data):
            sheet.cell(row=index+1,column=k+1,value=str(item[v]))

    # 写入文件
    workbook.save(path)


# 导入学生信息
def import_student_excel(request):
    # 从excel批量导入学生信息
    #  接收excel文件存储到Media文件夹
    rev_file = request.FILES.get('excel')
    # 判断是否有文件
    if not rev_file:
        return JsonResponse({'code':0,'msg':'Excel文件不存在!'})
    # 获取一个唯一的名字 uuid +hash
    new_name = get_random_str()
    # 准备写入的url
    file_path = os.path.join(settings.MEDIA_ROOT,new_name + os.path.splitext(rev_file.name)[1])
    # 写入到本次磁盘
    try:
        f = open(file_path,'wb')
        for i in rev_file.chunks():
            f.write(i)
        f.close()
    except Exception as e:
        return JsonResponse({"code":0,"msg":str(e)})

    # 读取存储在Media文件夹的数据
    ex_students = read_excel_dict(file_path)

    # 把读取的数据存储到数据库
    success =0
    error = 0
    error_sons = []

    # 开始遍历
    for one_student in ex_students:
        try:
            obj_student = StudentI.objects.create(sno=one_student['sno'], name=one_student['name'], gender=one_student['gender'],
                                                      birthday=one_student['birthday'],mobile=one_student['mobile'],
                                                   email=one_student['email'],address=one_student['address'])
            # 计数
            success +=1
        except:
            # 如果失败了
            error += 1
            error_sons.append(one_student['sno'])

    # 返回 导入信息
    obj_student = Student.objects.all().values()
    students = list(obj_student)
    return JsonResponse({'code':1,'success':success,'error':error,'errors':error_sons,'data':students})


# -------Django 原生------
def get_students(request):
    # 获取所有学生的信息
    try:
        # 使用ORM获取所有学生信息
        obj_students = StudentI.objects.all().values()
        # 把外层的容器转为list
        students = list(obj_students)
        # 返回
        return JsonResponse({"code":1,'data':students})
    except Exception as e:
        # 出现异常 返回
        return JsonResponse({"code":0,"msg":"获取学生信息出现异常，具体错误:" + str(e)})


def add_student(request):
    # 添加数据库
    json_str = request.body
    data = json.loads(json_str)
    try:
        # 添加数据库
        obj_student = StudentI(sno=data['sno'], name=data['name'], gender=data['gender'],
                              birthday=data['birthday'], mobile=data['mobile'],
                              email=data['email'], address=data['address'], image=data['image'])
        # 执行添加
        obj_student.save()
        # 使用orm获取所有学生信息，并把对象转为字典格式
        obj_students = StudentI.objects.all().values()
        # 把外层的容器转为list
        students = list(obj_students)
        # 返回
        return JsonResponse({"code":1,"data":students})

    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "添加到数据库出现异常，具体原因：" + str(e)})


def is_exists_sno(request):
    # 判断学号是否存在
    json_str = request.body
    data = json.loads(json_str)
    # 进行校验
    try:
        obj_students = StudentI.objects.filter(sno=data['sno'])
        if obj_students.count() == 0:
            return JsonResponse({'code':1,'exists':False})
        else:
            return JsonResponse({'code':1,'exists':True})
    except Exception as e:
        return JsonResponse({"code":0,'msg':"校验学号失败，具体原因:" + str(e)})


def delete_student(request):
    # 删除一条学生信息
    json_str = request.body
    data = json.loads(json_str)
    try:
        # 查找到要修改的学生信息
        obj_student = StudentI.objects.get(sno=data['sno'])
        # 删除
        obj_student.delete()
        # 使用orm获取所有学生信息，并把对象转为字典格式
        obj_students = StudentI.objects.all().values()
        # 把外层的容器转为list
        students = list(obj_students)
        return JsonResponse({"code":1,'data':students})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "删除学生信息写入数据库出现异常，具体原因：" + str(e)})


def delete_students(request):
    """批量删除学生信息"""
    # 接收前端传递过来的值
    json_str = request.body
    data = json.loads(json_str)
    try:
        # 遍历传递的集合
        for one_student in data['student']:
            # 查询当前记录
            obj_student = StudentI.objects.get(sno=one_student['sno'])
            # 执行删除
            obj_student.delete()
        # 使用ORM获取所有学生信息 并把对象转为字典格式
        obj_students = StudentI.objects.all().values()
        # 把外层的容器转为List
        students = list(obj_students)
        # 返回
        return JsonResponse({'code': 1, 'data': students})
    except Exception as e:
        return JsonResponse({'code': 0, 'msg': "批量删除学生信息写入数据库出现异常，具体原因：" + str(e)})


def update_student(request):
    """修改学生到数据库"""
    # 接收前端传递过来的值
    data = json.loads(request.body.decode("utf-8"))
    try:
        # 查找到要修改的学生信息
        obj_student = StudentI.objects.get(sno=data['sno'])
        # 依次修改
        obj_student.name = data['name']
        obj_student.gender = data['gender']
        obj_student.birthday = data['birthday']
        obj_student.mobile = data['mobile']
        obj_student.email = data['email']
        obj_student.address = data['address']
        obj_student.image = data['image']
        # 保存
        obj_student.save()
        # 使用ORM获取所有学生信息 并把对象转为字典格式
        obj_students = StudentI.objects.all().values()
        # 把外层的容器转为List
        students = list(obj_students)
        # 返回
        return JsonResponse({'code': 1, 'data': students})
    except Exception as e:
        return JsonResponse({'code':0 , 'msg': "修改保存到数据库出现异常，具体原因：" + str(e)})